// https://segmentfault.com/a/1190000017008697
const webpack = require('webpack');

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
// 拼接路径
const resolve = dir => require('path').join(__dirname, dir);

// 开启gzip压缩
const CompressionWebpackPlugin = require('compression-webpack-plugin');
const zopfli = require("@gfx/zopfli");
const BrotliPlugin = require("brotli-webpack-plugin");
const productionGzipExtensions = /\.(js|css|json|txt|html|ico|svg)(\?.*)?$/i;

// 增加环境变量
// process.env.VUE_APP_VERSION = require('./package.json').version;
// process.env.VUE_APP_BUILD_TIME = require('dayjs')().format('YYYY-M-D HH:mm:ss');

// 基础路径 注意发布之前要先修改这里
let publicPath = '/';

module.exports = {
    // 根据你的实际情况更改这里
    publicPath,
    lintOnSave: false,
    // 生产打包时不输出map文件，增加打包速度
    productionSourceMap: false,
    // 这里写你调用接口的基础路径，来解决跨域，如果设置了代理，那你本地开发环境的axios的baseUrl要写为 '' ，即空字符串
    devServer: {
        publicPath // 和 publicPath 保持一致
    },
    css: {
        // 将组建内的css提取到一个单独的ｃｓｓ文件中（只在生产环境中）
        // 好像有点开心的太早，修改css部分的内容并没有自动更新，原来的vue.config.js中的css配置搞的鬼。在css 的相关配置中多了extract:true的这一条配置，注释掉之后就可以自动更新。
        // extract:true
        // 是否开启 CSS source map？
        sourceMap: false,
        // 为预处理器的 loader 传递自定义选项。比如传递给
        // sass-loader 时，使用 `{ sass: { ... } }`。
        loaderOptions: {
            // 向全局sass样式传入共享的全局变量
            sass: {
                data: `@import '~@/assets/style/public.less';`
            }
        },
        // 为所有的 CSS 及其预处理文件开启 CSS Modules。
        // 这个选项不会影响 `*.vue` 文件。
        // modules: false
    },
    configureWebpack: config => {
        // 生产环境插件
        // 还可以开启比gzip体验更好的Zopfli压缩详见https://webpack.js.org/plugins/compression-webpack-plugin
        if (process.env.NODE_ENV === 'production') {
            const plugins = [];
            plugins.push(
                new CompressionWebpackPlugin({
                    algorithm(input, compressionOptions, callback) {
                        return zopfli.gzip(input, compressionOptions, callback);
                    },
                    compressionOptions: {
                        numiterations: 15
                    },
                    minRatio: 0.99,
                    test: productionGzipExtensions
                })
            );
            plugins.push(
                new BrotliPlugin({
                    test: productionGzipExtensions,
                    minRatio: 0.99
                })
            );
            // 每次生成dist目录前先删除dist目录
            plugins.push(new CleanWebpackPlugin());
            // 解构
            config.plugins = [
                ...config.plugins,
                ...plugins
            ];

            config.optimization.minimizer[0].options.terserOptions.compress.warnings = false;
            config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true;
            config.optimization.minimizer[0].options.terserOptions.compress.drop_debugger = true;
            config.optimization.minimizer[0].options.terserOptions.compress.pure_funcs = ['console.log']
        }

        // 配置externals
        // https://segmentfault.com/a/1190000017008697
        // 防止将某些 import 的包(package)打包到 bundle 中，而是在运行时(runtime)再去从外部获取这些扩展依赖
        // /属性名jquery指的是  import  $ from 'jquery'中的  'jquery'
        // 属性值 jQuery指的是jquery插件暴露出来的全局对象名。按理来说$应该也是可以写在属性值里面的，（也是jquery暴露的啊，但我没试过行不行）。
        config.externals = {
            vue: 'Vue',
            vuex: 'Vuex',
            axios: 'axios',
            lodash: '_',
            jquery: '$',
            moment: 'moment',
            'semantic-ui-css': 'semantic-ui-css',
            'vue-router': 'VueRouter'
        }
    },
    // 默认设置: https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-service/lib/config/base.js
    // unpkg.com/react/
    // 访问https://unpkg.com/element-ui/lib/theme-chalk/index.css获取最新版本
    // https://unpkg.com/browse/semantic-ui@2.4.2/dist/
    chainWebpack: config => {
        const cdn = {
            css: ['//unpkg.com/semantic-ui@2.4.2/dist/semantic.min.css'],
            js: [
                '//unpkg.com/vue@2.6.10/dist/vue.min.js', // 访问https://unpkg.com/vue/dist/vue.min.js获取最新版本
                '//unpkg.com/vue-router@3.0.6/dist/vue-router.min.js',
                '//unpkg.com/vuex@3.1.1/dist/vuex.min.js',
                '//unpkg.com/axios@0.19.0/dist/axios.min.js',
                '//unpkg.com/moment@2.24.0/min/moment.min.js',
                '//unpkg.com/moment@2.24.0/locale/zh-cn.js',
                '//unpkg.com/jquery@3.4.1/dist/jquery.min.js',
                '//unpkg.com/semantic-ui@2.4.2/dist/semantic.min.js'
            ]
        };

        // html中添加cdn
        config.plugin('html').tap(args => {
            args[0].cdn = cdn;
            return args
        });

        // 不参与打包，直接cdn
        // config.plugin("ignore")
        //     .use(
        //         new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn$/)
        //     );

        /**
         * 删除懒加载模块的 prefetch preload，降低带宽压力
         * https://cli.vuejs.org/zh/guide/html-and-static-assets.html#prefetch
         * https://cli.vuejs.org/zh/guide/html-and-static-assets.html#preload
         * 而且预渲染时生成的 prefetch 标签是 modern 版本的，低版本浏览器是不需要的
         */
        config.plugins.delete('prefetch').delete('preload');

        // 添加打包分析
        // https://www.cnblogs.com/hss-blog/p/10244315.html
        if (process.env.VUE_APP_IS_ANALYZ === 'TRUE') {
            config.plugin('webpack-report')
                .use(BundleAnalyzerPlugin, [{
                    //  可以是`server`，`static`或`disabled`。
                    //  在`server`模式下，分析器将启动HTTP服务器来显示软件包报告。
                    //  在“静态”模式下，会生成带有报告的单个HTML文件。
                    //  在`disabled`模式下，你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
                    analyzerMode: 'static',
                    //  将在“服务器”模式下使用的主机启动HTTP服务器。
                    analyzerHost: '127.0.0.1',
                    //  将在“服务器”模式下使用的端口启动HTTP服务器。
                    analyzerPort: 8888,
                    //  路径捆绑，将在`static`模式下生成的报告文件。
                    //  相对于捆绑输出目录。
                    reportFilename: 'report.html',
                    //  模块大小默认显示在报告中。
                    //  应该是`stat`，`parsed`或者`gzip`中的一个。
                    //  有关更多信息，请参见“定义”一节。
                    defaultSizes: 'parsed',
                    //  在默认浏览器中自动打开报告
                    openAnalyzer: true,
                    //  如果为true，则Webpack Stats JSON文件将在bundle输出目录中生成
                    generateStatsFile: false,
                    //  如果`generateStatsFile`为`true`，将会生成Webpack Stats JSON文件的名字。
                    //  相对于捆绑输出目录。
                    statsFilename: 'stats.json',
                    //  stats.toJson（）方法的选项。
                    //  例如，您可以使用`source：false`选项排除统计文件中模块的来源。
                    //  在这里查看更多选项：https：  //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
                    statsOptions: null,
                    logLevel: 'info' // 日志级别。可以是'信息'，'警告'，'错误'或'沉默'。
                }]);
        }

        config.plugin('provide')
            .use(webpack.ProvidePlugin, [{
                $: 'jquery',
                jquery: 'jquery',
                jQuery: 'jquery',
                'window.jQuery': 'jquery',
                semantic: 'semantic-ui-css',
                Semantic: 'semantic-ui-css',
                'semantic-ui': 'semantic-ui-css'
            }]);
        // 解决 cli3 热更新失效 https://github.com/vuejs/vue-cli/issues/1559
        // 只要在chainwebpack的配置项下加一行config.resolve.symlinks(true)这样我们修改保存.vue文件以及js代码就会自动刷新，
        config.resolve.symlinks(true);

        // 创建 import 或 require 的别名，来确保模块引入变得更简单。
        config.resolve
            .alias
            .set('@', resolve('src'))
            .set('vue$', 'vue/dist/vue.esm.js')
            .set('@api', resolve('src/api'))
            .set('@assets', resolve('src/assets'))
            .set('@scss', resolve('src/assets/scss'))
            .set('@components', resolve('src/components'))
            .set('@plugins', resolve('src/plugins'))
            .set('@views', resolve('src/views'))
            .set('@router', resolve('src/router'))
            .set('@store', resolve('src/store'))
            .set('@layouts', resolve('src/layouts'))
            .set('@static', resolve('src/static'));

        // markdown
        config.module
            .rule('md')
            .test(/\.md$/)
            .use('text-loader')
            .loader('text-loader')
            .end();

        // image exclude
        config.module
            .rule('images')
            .test(/\.(png|jpe?g|gif|webp|svg)(\?.*)?$/)
            .exclude
            .add(resolve('src/assets/svg-icons/icons'))
            .end();

        // 判断环境加入模拟数据
        if (process.env.VUE_APP_BUILD_MODE === 'MOCK') {
            config.entry('app').add('@/mock').end()
        }
    },
};
